/*
Script: Drag.Move.js
  A Drag extension that provides support for the constraining of draggables to containers and droppables.

  License:
    MIT-style license.

  Authors:
    Valerio Proietti
    Tom Occhinno
    Jan Kassens*/

Drag.Move = new Class({

  Extends: Drag,

  options: {/*
    onEnter: $empty(thisElement, overed),
    onLeave: $empty(thisElement, overed),
    onDrop: $empty(thisElement, overed, event),*/
    droppables: [],
    container: false,
    precalculate: false,
    includeMargins: true,
    checkDroppables: true
  },

  initialize: function(element, options){
    this.parent(element, options);
    this.droppables = $$(this.options.droppables);
    this.container = $(this.options.container);
    if (this.container && $type(this.container) != 'element') this.container = $(this.container.getDocument().body);

    var position = this.element.getStyle('position');
    if (position=='static') position = 'absolute';
    if ([this.element.getStyle('left'), this.element.getStyle('top')].contains('auto')) this.element.position(this.element.getPosition(this.element.offsetParent));
    this.element.setStyle('position', position);

    this.addEvent('start', this.checkDroppables, true);

    this.overed = null;
  },

  start: function(event){
    if (this.container){
      var ccoo = this.container.getCoordinates(this.element.getOffsetParent()), cbs = {}, ems = {};

      ['top', 'right', 'bottom', 'left'].each(function(pad){
        cbs[pad] = this.container.getStyle('border-' + pad).toInt();
        ems[pad] = this.element.getStyle('margin-' + pad).toInt();
      }, this);

      var width = this.element.offsetWidth + ems.left + ems.right;
      var height = this.element.offsetHeight + ems.top + ems.bottom;

      if (this.options.includeMargins) {
        $each(ems, function(value, key) {
          ems[key] = 0;
        });
      }
      if (this.container == this.element.getOffsetParent()) {
        this.options.limit = {
          x: [0 - ems.left, ccoo.right - cbs.left - cbs.right - width + ems.right],
          y: [0 - ems.top, ccoo.bottom - cbs.top - cbs.bottom - height + ems.bottom]
        };
      } else {
        this.options.limit = {
          x: [ccoo.left + cbs.left - ems.left, ccoo.right - cbs.right - width + ems.right],
          y: [ccoo.top + cbs.top - ems.top, ccoo.bottom - cbs.bottom - height + ems.bottom]
        };
      }

    }
    if (this.options.precalculate){
      this.positions = this.droppables.map(function(el) {
        return el.getCoordinates();
      });
    }
    this.parent(event);
  },

  checkAgainst: function(el, i){
    el = (this.positions) ? this.positions[i] : el.getCoordinates();
    var now = this.mouse.now;
    return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top);
  },

  checkDroppables: function(){
    var overed = this.droppables.filter(this.checkAgainst, this).getLast();
    if (this.overed != overed){
      if (this.overed) this.fireEvent('leave', [this.element, this.overed]);
      if (overed) this.fireEvent('enter', [this.element, overed]);
      this.overed = overed;
    }
  },

  drag: function(event){
    this.parent(event);
    if (this.options.checkDroppables && this.droppables.length) this.checkDroppables();
  },

  stop: function(event){
    this.checkDroppables();
    this.fireEvent('drop', [this.element, this.overed, event]);
    this.overed = null;
    return this.parent(event);
  }

});

Element.implement({

  makeDraggable: function(options){
    var drag = new Drag.Move(this, options);
    this.store('dragger', drag);
    return drag;
  }

});